﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ROrganizer.UI.Controllers;
using ROrganizer.UI.Forms.Core;
using ROrganizer.UI.Models;

namespace ROrganizer.UI.Forms
{
    internal partial class CrawlerResultsForm : Form
    {
        private readonly CrawlerResultsFormController controller;
        private readonly GroupManager<CrawlerResultsFormController.Result, object> grouper;

        public CrawlerResultsForm()
        {
            this.controller = new CrawlerResultsFormController(exceptioner: this.ProcessException);
            this.InitializeComponent();

            this.grouper = new GroupManager<CrawlerResultsFormController.Result, object>(this.olvEntries);
            this.InitializeGroups();

            this.olvEntries.Sort(this.chTitle, SortOrder.Ascending);
            this.controller.Results.CollectionChanged += this.OnChanged;
            this.controller.Changed += this.OnStateChanged;
        }

        private void InitializeGroups()
        {
            this.grouper.SetFormat<double>(this.chConfidence, Formatter.FormatPercent);
            this.grouper.SetFormat<short?>(this.chRating, Formatter.FormatRating);
            this.grouper.SetFormat<long>(this.chSize, Formatter.FormatSize);
            this.grouper.SetFormat<Resolution>(this.chResolution, Formatter.FormatResolution);
            this.grouper.SetFormat<int>(this.chRuntime, Formatter.FormatRuntime);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            this.olvEntries.Normalize();

            this.RefreshActions();
            this.controller.Refresh();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            e.Cancel = this.controller.IsWorking;
            base.OnClosing(e);
        }

        private void OnChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Reset)
                this.olvEntries.ClearObjects();

            if (e.OldItems != null)
                this.olvEntries.RemoveObjects(e.OldItems);

            if (e.NewItems != null)
                this.olvEntries.AddObjects(e.NewItems);
        }

        private void OnStateChanged(object sender, EventArgs e)
        {
            if (this.SynchronizeInvocation(this.OnStateChanged, sender, e))
            {
                this.pbMain.Value = Math.Min(this.controller.Progress, this.pbMain.Maximum);
                this.RefreshActions();
            }
        }

        private void OnCancel(object sender, EventArgs e)
        {
            this.ExecuteAndWatch(this.controller.Cancel);
        }

        private void OnReport(object sender, EventArgs e)
        {
            this.ExecuteAndWatch(this.controller.Report, this, this.olvEntries.SelectedObjects.OfType<CrawlerResultsFormController.Result>().ToArray());
        }

        private void RefreshActions()
        {
            this.pbMain.Visible = this.controller.IsWorking;
            this.btnCancel.Enabled = this.controller.CanCancel();
            this.tsmiReport.Enabled = this.controller.CanReport(this.olvEntries.SelectedObjects.OfType<CrawlerResultsFormController.Result>().ToArray());
        }
    }
}
